/*MyPhotoIndex Free Photo Organizer <www.myphotoindex.com>
  Copyright (C) <2006-2007>  <Asaf Yarkoni asaf@myphotoindex.com>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.*/

#include "stdafx.h"
#include "DCRawPlugin.h"
#include "string.h"
#include "RawImageData.h"
#include "time.h"

extern "C"
{
	int main (int argc, char **argv, char* outputFileName);
	extern int half_size;

	extern char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64];
	extern float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len;
	extern unsigned short raw_height, raw_width, height, width, top_margin, left_margin;
	extern unsigned short shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height;
	extern time_t timestamp;
}

using namespace MyPhotoIndex::Interfaces::ImageFormatProviders;
using namespace MyPhotoIndex::Interfaces::Imaging;
using namespace System::Runtime::InteropServices;
using namespace MyPhotoIndex::Utilities;


		String^ RawPlugin::Extention::get()
		{ 
			return m_fileExtention;
		}

        void RawPlugin::SaveImage(Image^ image, IImageData^ imageData, String^ fileName)
		{
			throw gcnew NotImplementedException();
		}
		void RawPlugin::SaveImage(Image^ image, IImageData^ imageData, IO::Stream^ stream)
		{
			throw gcnew NotImplementedException();
		}

		bool RawPlugin::CanRotate::get()
		{
			return false;
		}

		bool RawPlugin::IsVideo::get()
		{
			return false;
		}

		bool RawPlugin::IsCachable::get()
		{
			return true;
		}

		bool RawPlugin::CanSave::get()
		{
			return false;
		}

        void RawPlugin::Rotate(String^ fileName, RotateFlipType rotationType, Image^% thumbnail, Size% newImageSize)
		{
			throw gcnew NotImplementedException();
		}

		bool RawPlugin::Exists(String^ path)
		{
			return IO::File::Exists(path);
		}

		bool RawPlugin::CanDelete(String^ path)
        {
            return Exists(path);
        }

        void RawPlugin::Delete(String^ path)
        {
            try
            {
				Microsoft::VisualBasic::FileIO::FileSystem::DeleteFile(path, Microsoft::VisualBasic::FileIO::UIOption::OnlyErrorDialogs, 
                     Microsoft::VisualBasic::FileIO::RecycleOption::SendToRecycleBin);
            }
            catch (Exception^ ex)
            {
				Logger::Log(ex);
            }
        }

		void RawPlugin::CopyTo(IImageData^ imageData, String^ newMediaPath)
        {
			IO::File::Copy(imageData->FileName, newMediaPath, false);
        }
		
		Image^ RawPlugin::LoadImage(IImageData^ imageData)
		{
			return LoadImage(imageData, Size::Empty);
		}

        Image^ RawPlugin::LoadImage(IImageData^ imageData, Size requestedSize)
		{
			return LoadImage(imageData->FileName, requestedSize);
		}

        Image^ RawPlugin::LoadImage(String^ fileName, Size requestedSize)
		{
			try
            {
				if (true == String::IsNullOrEmpty(fileName))
                {
                    return nullptr;
                }

				Image^ image = nullptr;
				if(requestedSize != Size::Empty)
				{
					image = GetThumbnail (fileName, true, Size::Empty);
					if(image != nullptr)
					{
						if(image->Width < requestedSize.Width ||
							image->Height < requestedSize.Height)
						{
							delete image;
							image = nullptr;
						}
					}
				}

				if(image == nullptr)
				{
					image = GetImage(fileName, (requestedSize == Size::Empty)?0:-1);
				}

				if (requestedSize == Size::Empty)
                {
                    return image;
                }

                Using use(image);
                {
                    try
                    {
						Size realPicSize = ImageAlgo::GetImageProportionalSize(SizeF((float)image->Width, (float)image->Height), SizeF((float)requestedSize.Width, (float)requestedSize.Height));
                        Image^ resizedImage = gcnew Bitmap(realPicSize.Width, realPicSize.Height, image->PixelFormat);
						Graphics^ graphic = Graphics::FromImage(resizedImage);
						Using use1 (graphic);
                        {
							graphic->CompositingQuality = CompositingQuality::HighQuality;
							graphic->SmoothingMode = SmoothingMode::HighQuality;
							graphic->InterpolationMode = InterpolationMode::HighQualityBicubic;
                            Rectangle rectangle = Rectangle(0, 0, realPicSize.Width, realPicSize.Height);
                            graphic->DrawImage(image, rectangle);
                        }

                        return resizedImage;
                    }
                    catch (Exception^ ex)
                    {
						Logger::Log(ex);
                    }

                    return nullptr;
                }
            }
			catch (IO::FileNotFoundException^)
            {
                return nullptr;
            }
            catch (OutOfMemoryException^)
            {
                return nullptr;
            }
		}

        IImageMetaData^ RawPlugin::GetImageMetaData(String^ fileName)
		{
			if (false == IO::File::Exists(fileName))
			{
				throw gcnew IO::FileNotFoundException(fileName);
			}

			Lock lock(m_lock);

			Args argv;
			argv.Add("-i");
			argv.Add("-v");
			argv.Add(fileName);

			main(argv.Count, argv, "");

			RawImageData^ imageData = gcnew RawImageData();

			struct tm* t = _gmtime64(&timestamp);
			t->tm_year += 1900;
			t->tm_mon += 1;
			imageData->DateTaken = DateTime(t->tm_year, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);

			imageData->DateDigitized = imageData->DateTaken;
			imageData->ImageDescription = gcnew String(desc);
			imageData->CameraMaker = gcnew String(make);
			imageData->CameraModel = gcnew String(model);
			imageData->FlashStatus = (CameraFlashStatus)(int)flash_used;
			imageData->IsoSpeed = (int)iso_speed;
			imageData->ExposureTime = String::Empty;//shutter;
			imageData->Aperture = aperture;
			imageData->FocalLength = focal_len;
			imageData->ImageWidth = width;
			imageData->ImageHeight = height;
			imageData->LastModifiedDateTime = IO::File::GetLastWriteTimeUtc(fileName);

			return imageData;
		}

		DateTime RawPlugin::GetImageMediaLastUpdated(String^ fileName)
        {
			return IO::File::GetLastWriteTimeUtc(fileName);
        }

		String^ RawPlugin::GetImageMediaSignature(String^ fileName)
        {
			return FileUtilities::GetFileMD5Signature(fileName);
        }

        void RawPlugin::SetImageMetaData(IImageData^ imageData, String^ fileName)
		{
		}

		Image^ RawPlugin::GetThumbnail(String^ fileName, Size size)
		{
			return GetThumbnail(fileName, false, size);
		}
	
		Image^ RawPlugin::GetThumbnail(String^ fileName, bool origSize, Size size)
		{
			Image^ thumbnail = nullptr;

			try
			{
				thumbnail = ExtractImage(fileName, true, -1);
				if(origSize == true && 
					thumbnail != nullptr)
				{
					return thumbnail;
				}

				Using use(thumbnail);
				Size realPicSize = ImageAlgo::GetImageProportionalSize(SizeF((float)thumbnail->Width, (float)thumbnail->Height), SizeF(size.Width, size.Height));
                return gcnew Bitmap(thumbnail, realPicSize.Width, realPicSize.Height);
			}
			catch (IO::FileNotFoundException^)
			{
				return nullptr;
			}
			catch (Exception^ ex)
			{
				return nullptr;
			}

			if(thumbnail == nullptr)
			{
				thumbnail = LoadImage(fileName, Size(320, 240));
			}

			return thumbnail;
		}

		Image^ RawPlugin::GetImage(String^ rawFileName, int quality)
		{
			return ExtractImage(rawFileName, false, quality);
		}
		Image^ RawPlugin::ExtractImage(String^ rawFileName, bool thumbnail, int quality)
		{
			if (false == IO::File::Exists(rawFileName))
			{
				throw gcnew IO::FileNotFoundException(rawFileName);
			}

			Lock lock(m_lock);
			half_size = 0;

			Args argv;
			argv.Add("-T");
			argv.Add(thumbnail? "-e" : (quality == -1)?"-h":"-v");
			argv.Add(rawFileName);

			String^ tempPath = System::IO::Path::GetTempPath();
			String^ tempFile = System::IO::Path::Combine(tempPath, System::IO::Path::GetTempFileName());
			
			char* str2 = (char*)(void*)Marshal::StringToHGlobalAnsi(tempFile);
			int status = main(argv.Count, argv, str2);
			if(thumbnail == true && status != 0)
			{//could not load thumbnail
				Args argv;
				argv.Add("-T");
				argv.Add("-v");
				argv.Add(rawFileName);
				status = main(argv.Count, argv, str2);
			}

			Marshal::FreeHGlobal((IntPtr)str2);

			Image^ newImage = nullptr;
			if(status == 0)
			{
				IO::FileStream^ fs = gcnew IO::FileStream(tempFile, IO::FileMode::Open, IO::FileAccess::Read);
				Image^ image = Image::FromStream(fs);
				newImage = gcnew Bitmap(image, image->Width, image->Height);
				delete image;
				fs->Close();
			}

			IO::File::Delete(tempFile);

			return newImage;
		}

		